#include "um_basic_types.h"
#include "umapi_os_list.h"
#include "umapi_os.h"
#include "umapi_libc.h"
#include "umapi_file.h"
#include "umapi_socket.h"
#include "libavformat/avformat.h"
#include "libavformat/avio.h"
#include "libavformat/version.h"
#include "libavcodec/avcodec.h"
#include "libavutil/avstring.h"
#include "libavutil/dict.h"
#include "libswresample/swresample.h"
#include "umP2p.h"
#include "httpTools.h"
#include "umlog.h"
#include "cJSON.h"

#define TARGET "UMP2P"
#define DEBUGLEVEL p2pLevel
static int p2pLevel ;
UM_VOID setP2pDebug(UM_S32 level)
{
	p2pLevel = level;
}

typedef struct
{
	ServerContext context;
	UM_VOID *epoll;	
	UM_HANDLE mutexHandle,taskHandle;
	struct umapi_list_head clients;
}P2pServerContext;

typedef struct
{
	P2pServerContext *client;
	UMAPI_SOCKET_ADDR clientAddr;
	UM_HANDLE fd;
	UM_CHAR deviceCode[36];
	UM_CHAR uid[100];
	UM_CHAR ei[20];
	UM_CHAR ep[8];
	UM_CHAR type[4];
	UM_CHAR cmdbuff[2048];
	UM_BOOL readHeadflag;
}ClientParam;

static UM_S32 disConnectClient(UM_HANDLE fd, UM_VOID *param)
{
	ClientParam *c = ((UM_EFD*)param)->pri;
	P2pServerContext *s = (P2pServerContext*)c->client;
	if(c->readHeadflag)
	{
		S_HttpMsg hMsg;
		umapi_snprintf(hMsg.host, sizeof(hMsg.host), "%s", gSystemData.voHost);
		hMsg.port = gSystemData.voPort;
		umapi_snprintf(hMsg.path, sizeof(hMsg.path), "%s?flag=0", gSystemData.vohandlePath);
		umapi_snprintf(hMsg.body, sizeof(hMsg.body), "%s", c->cmdbuff);
		LOGI("client:%d, send to %s %s", c->fd, hMsg.path, hMsg.body);
		hMsg.p = s->epoll;
		hMsg.method = 1;
		callsystem(&hMsg);
	}
	umapi_free(c);
	return UM_SUCCESS;
}
static UM_CHAR *getSrcPath(UM_HANDLE client, UM_U8 ** srcPath)
{
	UM_CHAR buff[4096] = {0};
	UM_S32 index = 0;
	UM_CHAR *path = UM_NULL;
	while(umapi_socket_recv(client, &buff[index++],1, 0) == 1 )
	{
		if(index > 2 && buff[index-2] == '\r' && buff[index-1] == '\n')
		{
			goto READOK;
		}
		else if(index >= 4095)
			break;
	}
	LOGE("client:%d read srcPath Fail index:%d", client,index );
	return UM_NULL;
READOK:	
	path = umapi_malloc(umapi_strlen(buff) - 1);
	if(path && index >1 )
	{
		umapi_memcpy(path, buff, umapi_strlen(buff) -2);
		path[umapi_strlen(buff) - 2] = '\0';
	}
	else
	{
		LOGE("malloc fail buff:%s, :%d", buff, index);
	}
	*srcPath = path;
	return path;
}

static UM_S32 readClient(UM_HANDLE fd, UM_VOID *param)
{
	ClientParam *c = ((UM_EFD*)param)->pri;
	UM_U8 *srcPath = UM_NULL;
	UM_EFD *ufd = (UM_EFD *)param;
	cJSON *urlRoot = UM_NULL;
	if(getSrcPath(c->fd, &srcPath) == UM_NULL)
	{
		LOGE("get srcPath Fail");
		//ufd->status = 0;
		removeFd(c->client->epoll, ufd);
		return UM_FAILURE;
	}
	if(!c->readHeadflag)
	{
		S_HttpMsg hMsg;
		c->readHeadflag = UM_TRUE;
		cJSON *json =  UM_NULL;
		UM_CHAR url[200];
		if(srcPath[0] == '{')
			json = cJSON_Parse(srcPath);
		if(!json)	
		{		
			LOGI("client:%d read srcUrl:%s readCount:%d", c->fd, srcPath,ufd->readCount );
			readStringByUrl(srcPath, "deviceCode", c->deviceCode);
			readStringByUrl(srcPath, "uid", c->uid);
			if(umapi_strcmp(c->uid, "[]"))
			{
				UM_CHAR uids[200];
				umapi_snprintf(uids,sizeof(uids),"[\"%s\"]", c->uid);
				umapi_snprintf(c->uid, sizeof(c->uid),"%s", uids);
			}
			readStringByUrl(srcPath, "type", c->type);
			readStringByUrl(srcPath, "e", c->ei);
			readStringByUrl(srcPath, "p", c->ep);
			umapi_sprintf(url, "p2p://%s:%s/%s",
				c->ei, c->ep, c->deviceCode);
		}
		if(!json)
		{
			umapi_snprintf(c->cmdbuff, sizeof(c->cmdbuff), 
				"{\"deviceCode\":\"%s\",\"type\":\"%s\",\"uid\":%s,\"url\":[\"%s\"]}",
				c->deviceCode, c->type, c->uid, url
				);
		}
		else
		{
			umapi_sprintf(url, "p2p://%s:%s/%s",
				cJSON_GetObjectItem(json, "e")->valuestring, 
				cJSON_GetObjectItem(json, "p")->valuestring, 
				cJSON_GetObjectItem(json, "deviceCode")->valuestring);
			cJSON_DeleteItemFromObject(json, "url");				
			urlRoot = cJSON_CreateArray();
			cJSON_AddItemToArray(urlRoot, cJSON_CreateString(url));
			cJSON_AddItemToObject(json, "url", urlRoot);
			UM_CHAR *out = cJSON_PrintUnformatted(json);
			umapi_sprintf(c->cmdbuff, "%s", out);
			cJSON_free(out);
			cJSON_Delete(json);
		}
		umapi_sprintf(hMsg.body, "%s", c->cmdbuff);
		umapi_sprintf(hMsg.host, "%s", gSystemData.voHost);
		hMsg.port = gSystemData.voPort;
		umapi_sprintf(hMsg.path,"%s?flag=%d", gSystemData.vohandlePath, 1);
		LOGI("client:%d, send to %s %s", fd, hMsg.path, hMsg.body);
		hMsg.method = 1;
		callsystem(&hMsg);
		c->readHeadflag = UM_TRUE;
	}
	umapi_free(srcPath);
	return UM_SUCCESS;
}

static UM_S32 connectClient(UM_HANDLE fd, UM_VOID *param
	,UM_EFD ** pefd
)
{
	P2pServerContext *c = ((UM_EFD*)param)->pri;
	ClientParam * cp = (ClientParam*)umapi_malloc(sizeof(ClientParam));
	umapi_memset(cp, 0, sizeof(ClientParam));
	cp->fd = fd;
	cp->client = c;
	umapi_socket_getpeername(fd, &cp->clientAddr);
	UM_EFD *p = um_ufd_malloc(fd, UM_NULL, readClient, disConnectClient, 0x20 | 1, cp);
	if(!p)
	{
		LOGS("malloc ufd Fail");
		umapi_free(cp);
		return UM_FAILURE;
	}
	LOGI("new connect fd:%d, %s:%d", fd, 
		umapi_socket_inet_ntoa(cp->clientAddr.addr.ipv4),cp->clientAddr.sin_port);
	*pefd = p;
	return UM_SUCCESS;
}

static UM_VOID serverTask(UM_VOID *param)
{
	P2pServerContext *c = (P2pServerContext*)param;
	UMAPI_SOCKET_ADDR ipaddr;
	ipaddr.addr.ipv4 = 0;
	ipaddr.sin_port = c->context.port;
	startEpoll(c->epoll, &ipaddr, connectClient, UM_NULL, UM_NULL, c
		,&c->context.fd
	);
}

static UM_S32 initP2pServer(UM_VOID* pServer, struct umapi_list_head *phead)
{
	P2pServerContext *s = (P2pServerContext*)pServer;
	struct umapi_list_head *pos, *n;
	umapi_list_for_each_safe(pos,n,phead)
	{
		KV *pkv = umapi_list_entry(pos,KV,h);
		LOGI("param {%s:%s}", pkv->key, pkv->value);
		if(umapi_strcmp(pkv->key,"port") == 0)
		{
			s->context.port = umapi_atoi(pkv->value);
		} else if (umapi_strcmp(pkv->key,"max") == 0)
		{
			s->context.maxClientCount = umapi_atoi(pkv->value);
		}
	}
	if(s->context.port == 0 || s->context.maxClientCount == 0)
	{
		umapi_free(s);
		return UM_FAILURE;
	}
	LOGI("create AoServer %d, max:%d", s->context.port, s->context.maxClientCount);
	s->context.mt = P2P;
	umapi_sprintf(s->context.codeType, "%s", "P2P");
	s->epoll = createEpoll(1024);
	umapi_os_mutex_create(UM_NULL,UM_OS_MUTEX_ATTR_RECURSIVE_NP,&s->mutexHandle);
	umapi_list_create(&s->clients);
	umapi_os_task_create(UM_NULL, serverTask, s,
                        UM_OS_TASK_PRIO_LEVEL_8, 0, &s->taskHandle);
	umapi_os_task_detach(s->taskHandle);
}
static Server *createServerContext()
{
	P2pServerContext * ret = (Server *)umapi_malloc(sizeof(P2pServerContext));
	umapi_memcpy(ret, &umP2p, sizeof(Server));
	return (Server*)ret;
}
static UM_CHAR *getUrl(UM_VOID *param)
{
}
static UM_S32 stopTranscode(UM_VOID* pServer,UM_VOID* pTranscode)
{

}
static UM_VOID* startTranscode(UM_VOID* pServer,UM_CHAR *src, UM_CHAR *dest)
{

}
static UM_VOID destroyServerContext(UM_VOID* pServer)
{
	return ;
}

static UM_BOOL matchProtol(UM_CHAR *protol)
{
	return protol && (umapi_strcmp(protol, "p2p") == 0);
}

Server umP2p = {
	.init = initP2pServer,
	.start = startTranscode,
	.stop = stopTranscode,
	.create = createServerContext,
	.destroy = destroyServerContext,
	.getUrl = getUrl,
	.match = matchProtol,
};

